//
//  HABleManager.m
//  EKLLighting
//
//  Created by Chris on 2021/4/30.
//

#import "HABleManager.h"
#import "NSData+Expand.h"
@interface HABleManager()

@property (nonatomic, assign) BOOL isStartAuthentication;

@property (nonatomic, assign) NSInteger currentTime;

@property (nonatomic, strong) NSData *bleLoginDete;

@property(nonatomic, strong) CBCharacteristic *writeCharacter;

@property(nonatomic, strong) CBCharacteristic *readCharacter;

@property(nonatomic, copy) SuccessConnectToPeriperalBlock successBlock;

@property(nonatomic, copy) FailConnectToPeriperalBlock failBlock;

@property(nonatomic, copy) CancelConnectToPeriperalBlock cancelBlock;

@property(nonatomic, copy) DiscoverPeriperalsBlock discoverPeriBlock;

@property(nonatomic, copy) DiscoverCharacteristicBlock discoverCharacteristicBlock;

@property(nonatomic, strong) dispatch_queue_t eklCommandQueue;

@property(nonatomic, strong) NSMutableDictionary *bleModelDictionary;

@end

@implementation HABleManager

+ (HABleManager *)sharedManager {
    static dispatch_once_t once;
    static id instance;
    dispatch_once(&once, ^{
        instance = [self new];
    });
    return instance;
}

- (instancetype)init{
    self = [super init];
    if (self){
        self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
        self.eklCommandQueue = dispatch_queue_create("EKL.ECOLOR.QUEUE", DISPATCH_QUEUE_SERIAL);
        self.bleModelDictionary = [NSMutableDictionary dictionary];
    }
    return self;
}

/*
 * 扫描
 * scan
 */
- (void)scanPeriperals:(_Nullable DiscoverPeriperalsBlock)discoverPeriperals{

    _discoverPeriBlock = discoverPeriperals;
    [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@(NO)}];
}

/*
 * 停止扫描
 * stop scan
 */
- (void)stopScanPeriperals{
    DDLogInfo(@"==========stopScanPeriperals");
    [self.centralManager stopScan];
}

/*
 * 连接
 * connect
 */
- (void)connectToPeripheral:(CBPeripheral *)peripheral success:(SuccessConnectToPeriperalBlock)success fail:(FailConnectToPeriperalBlock)fail characteristic:(DiscoverCharacteristicBlock)characteristic
{
    _currentPeri = peripheral;
    _successBlock = success;
    _failBlock = fail;
    DDLogInfo(@"=======bleConnected characteristic is: 014");
    _discoverCharacteristicBlock = characteristic;
    if (peripheral) {
        [self.centralManager connectPeripheral:peripheral options:nil];
    }
}

/*
 * 断开连接
 * cancel connect
 */
- (void)cancelConnectToPeripheral:(_Nullable CancelConnectToPeriperalBlock)cancel
{
    _cancelBlock = cancel;
    [self destroyBleConnect];
    _weakself;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (weakself.cancelBlock) {
            weakself.cancelBlock(nil, nil, nil);
            weakself.cancelBlock = nil;
        }
    });
}

- (void)destroyBleConnect
{
    _discoverCharacteristicBlock = nil;
    [_bleModelDictionary removeAllObjects];
    if (_currentPeri) {
        [self.centralManager cancelPeripheralConnection:_currentPeri];
    }
}


/*
 * 读取信号量
 * read RSSI
 */
- (void)readRSSIWithPeriperal:(CBPeripheral *)peripheral{
    [peripheral readRSSI];
}



- (void)handleRecvData:(NSData *)data peripheral:(CBPeripheral *)peripheral
{
    if(data.length < 4){
        return;
    }
    NSData *dataTag = [data subdataWithRange:NSMakeRange(0, 1)];
    NSString *dataTagStr = [dataTag toHexString];
    if([dataTagStr isEqualToString:@"fe"]){ //上报数据
        BOOL canParse = [self parserBLEData:data];
        if(canParse){
            NSString *cmdHeader =  [HABleManager dataToStringTag:data];
            HABleModel *bleModel = _bleModelDictionary[cmdHeader];
            if (bleModel) {
                [bleModel parserCmdData:data];
                if (bleModel.bleCompleHander) {
                    bleModel.bleCompleHander(bleModel);
                }
                [_bleModelDictionary removeObjectForKey:cmdHeader];
            }else{
                bleModel = [[HABleModel alloc] init];
                [bleModel parserCmdData:data];
                if([bleModel.Cmd isEqualToString:@"61"]){
                    [[NSNotificationCenter defaultCenter] postNotificationName:BLUETOOTHPOWERSTATUSCHANGE object:bleModel];
                }
            }
        }
    }else if([dataTagStr isEqualToString:@"fd"]){  //应答数据
        NSString *cmdHeader =  [HABleManager dataToStringTag:data];
        HABleModel *bleModel = _bleModelDictionary[cmdHeader];
        if (bleModel) {
            [bleModel parserCmdData:data];
            if (bleModel.bleCompleHander) {
                bleModel.bleCompleHander(bleModel);
            }
            [_bleModelDictionary removeObjectForKey:cmdHeader];
        }
    }
}

- (BOOL)parserBLEData:(NSData *)data{
    NSData *cmdData = [data subdataWithRange:NSMakeRange(3, 1)];
    short cmd = [cmdData ToByteShort];
    if(cmd == 1){
        if(data.length >= 5){
            NSData *stepData = [data subdataWithRange:NSMakeRange(4, 1)];
            int step = [stepData ToByteShort];
            if(step == 1){
                if(data.length == 21){
                    DDLogInfo(@"======收鉴权01处理");
                    self.isStartAuthentication = YES;
                    [self  bleLoginReply];
                }else{
                    DDLogInfo(@"======收鉴权01不处理");
                }
            }else if(step == 3){
                DDLogInfo(@"======收鉴权03");
                if(data.length >= 21){
                    NSData *decryData = [data subdataWithRange:NSMakeRange(5, 16)];
                    NSData *da =  [decryData aes128CBC:@"1234567890123456" iv:@"1234567890123456" mode:kCCDecrypt];
                    NSData *newData = [da subdataWithRange:NSMakeRange(0, 4)];
                    if([newData isEqualToData:[self.bleLoginDete subdataWithRange:NSMakeRange(0, 4)]]){
                          [self bleLoginVerify];
                    }
                }
            }
        }
        return NO;
    }else{
        return YES;
    }
}

- (NSInteger)getCurrentDay{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
    //设置时区,这个对于时间的处理有时很重要
    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
    [formatter setTimeZone:timeZone];
    NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
    return (long)[datenow timeIntervalSince1970];
}

- (NSData *)getTodayStrss{
    NSInteger currentTimeStamp = [self getCurrentDay];
    NSString *endStr = [NSString stringWithFormat:@"%lx",(long)currentTimeStamp];
    if (currentTimeStamp - self.currentTime < 2){
        return nil;
    }
    self.currentTime = currentTimeStamp;
    NSMutableData *data = [NSMutableData data];
    int idx;
    for(idx = 0; idx+ 2 <= endStr.length; idx+=2){
        NSRange range = NSMakeRange(endStr.length - idx - 2, 2);
        NSString *hexStr = [endStr substringWithRange:range];
        NSScanner *scanner = [NSScanner scannerWithString:hexStr];
        unsigned int intValue;
        [scanner scanHexInt:&intValue];
        [data appendBytes:&intValue length:1];
    }
    self.bleLoginDete = data;
    if(endStr.length < 32){
        Byte cmdbyte[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        [data appendBytes:cmdbyte length:12];
    }
    return [data aes128CBC:@"1234567890123456" iv:@"1234567890123456" mode:kCCEncrypt];
}
//主动下发授权指令
- (void)bleAuthentication{
    Byte cmdbyte[4] = {0xfe, 0x02, 0x00, 0x01};
    NSMutableData *newData = [NSMutableData data];
    [newData appendBytes:cmdbyte length:4];
    [HABleManager sendCommandData:newData completion:^(HABleModel * _Nonnull bleModel) {
        
    }];
}
//设备登录
- (void)bleLoginReply{
    Byte cmdbyte[5] = {0xfe, 0x13, 0x00, 0x01, 0x02};
    Byte *bytes = (Byte *)[[self getTodayStrss] bytes];
    if(bytes != nil){
        NSMutableData *newData = [NSMutableData data];
        [newData appendBytes:cmdbyte length:5];
        [newData appendBytes:bytes length:16];
        [HABleManager sendCommandData:newData completion:^(HABleModel * _Nonnull bleModel) {
            
        }];
    }
}
//设备登录校验
- (void)bleLoginVerify{
    Byte cmdbyte[5] = {0xfe, 0x03, 0x00, 0x01, 0x04};
    NSMutableData *newData = [NSMutableData data];
    [newData appendBytes:cmdbyte length:5];
    [HABleManager sendCommandData:newData completion:^(HABleModel * _Nonnull bleModel) {
    }];
}


#pragma mark - CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    DDLogInfo(@"======HABleManager centralManagerDidUpdateState=======");
    switch (central.state){
        case CBManagerStatePoweredOn:
            DDLogInfo(@"蓝牙开启且可用");
            break;
        case CBManagerStateUnknown:
            DDLogInfo(@"手机没有识别到蓝牙，请检查手机。"); break;
        case CBManagerStateResetting:
            DDLogInfo(@"手机蓝牙已断开连接，重置中。"); break;
        case CBManagerStateUnsupported:
            DDLogInfo(@"手机不支持蓝牙功能，请更换手机。"); break;
        case CBManagerStatePoweredOff:{
            _currentPeri.authorized = @(NO);
            DDLogInfo(@"蓝牙未打开"); break;
        }
        case CBManagerStateUnauthorized:
            break;
    }
    if([self.delegate respondsToSelector:@selector(centralHAManagerDidUpdateState:)]){
        [self.delegate centralHAManagerDidUpdateState:central];
    }
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI{
    peripheral.advertisementData = advertisementData;
    if (_discoverPeriBlock) {
        _discoverPeriBlock(central, peripheral, advertisementData, RSSI);
    }
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    _currentPeri = peripheral;
    NSString *bleName = [peripheral.advertisementData objectForKey:@"kCBAdvDataLocalName"];
    DDLogInfo(@"centralManager didConnectPeripheral: %@, %@", bleName, _currentPeri);
    if (_discoverCharacteristicBlock == nil) {
        [self destroyBleConnect];
        return;
    }
    DDLogInfo(@"=======bleConnected characteristic is: 012");
    if (_successBlock) {
        _successBlock(central, peripheral);
    }
    
    peripheral.delegate = self;
    CBUUID  *serviceUUID    = [CBUUID UUIDWithString:KRServiceUUID];
    NSArray  *serviceArray  = [NSArray arrayWithObjects:serviceUUID, nil];
    [peripheral discoverServices:serviceArray];
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    _currentPeri = nil;
    if (_failBlock) {
        _failBlock(central, peripheral, error);
    }
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    DDLogInfo(@"===========didDisconnectPeripheral name is:%@",peripheral.name);
    peripheral.authorized = @(NO);
    _currentPeri = nil;
    if (_cancelBlock) {
        _cancelBlock(central, peripheral, error);
        _cancelBlock = nil;
    }else {
        [[NSNotificationCenter defaultCenter] postNotificationName:BLUETOOTHDISCONNECTED object:peripheral];
    }
}

#pragma mark - CBPeripheralDelegate

- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error{
   
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    if (_discoverCharacteristicBlock == nil) {
        [self destroyBleConnect];
        return;
    }
    for (CBService *service in peripheral.services) {
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    if (_discoverCharacteristicBlock == nil) {
        [self destroyBleConnect];
        return;
    }
    for (CBCharacteristic *cha in service.characteristics){
        if ([cha.UUID.UUIDString isEqualToString:KRCharacteristicWrtieUUID]){
            //获取特征
            HABleManager *eleMgr = [HABleManager sharedManager];
            _writeCharacter = cha;
            eleMgr.writeCharacter = cha;
            if (_discoverCharacteristicBlock) {
                _discoverCharacteristicBlock(peripheral, service, error);
            }
        }
        if([cha.UUID.UUIDString isEqualToString:KRCharacteristicReadUUID]){
            HABleManager *eleMgr = [HABleManager sharedManager];
            _readCharacter = cha;
            eleMgr.readCharacter = cha;
            if (!eleMgr.readCharacter.isNotifying) {
                [eleMgr.currentPeri setNotifyValue:YES forCharacteristic:cha];
            }
            if (_discoverCharacteristicBlock) {
                _discoverCharacteristicBlock(peripheral, service, error);
            }
        }
    }
    
    for (CBCharacteristic *characteristic in service.characteristics) {
        if (characteristic.properties&CBCharacteristicPropertyRead || characteristic.properties&CBCharacteristicPropertyBroadcast) {
            [peripheral readValueForCharacteristic:characteristic];
        }
    }
    if(peripheral.authorized.boolValue){
        DDLogInfo(@"=======didDiscoverCharacteristicsForService authorized");
        [[NSNotificationCenter defaultCenter] postNotificationName:BLUETOOTHVERIFYSUCCESS object:nil];
    }
}

//读蓝牙数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    DDLogInfo(@"=====didUpdateValueForCharacteristic:%@,UUIDString is %@,snCode is %@",characteristic.value,characteristic.UUID.UUIDString,peripheral.snCode);
    if ([characteristic.UUID.UUIDString isEqualToString:KRCharacteristicReadUUID]){
        //获取特征
        NSData *data = characteristic.value;
        [self handleRecvData:data peripheral:peripheral];
    }
    if ([characteristic.UUID.UUIDString isEqualToString:KRCharacteristicWrtieUUID]){
        //获取特征
        NSData *data = characteristic.value;
        [self handleRecvData:data peripheral:peripheral];
    }

}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    if (error) {
        DDLogInfo(@"订阅失败,error:%@",error);
    }
    if (characteristic.isNotifying) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if(!self.isStartAuthentication){
                DDLogInfo(@"======send start authorize=====");
                [self bleAuthentication];
            }
        });
        DDLogInfo(@"订阅成功,isStartAuthentication is %d",self.isStartAuthentication);
    } else {
        DDLogInfo(@"取消订阅");
    }

}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
    DDLogInfo(@"=====didWriteValueForCharacteristic value:%@,UUID:%@",characteristic.value,characteristic.UUID.UUIDString);
}


//
+(NSString *)dataToStringTag:(NSData *)data{
    if(data.length >= 4){
        NSData *sdata = [data subdataWithRange:NSMakeRange(0, 4)];
        NSMutableData *freshData = [NSMutableData data];
        [freshData appendData:[sdata subdataWithRange:NSMakeRange(0, 1)]];
        [freshData appendData:[sdata subdataWithRange:NSMakeRange(2, 2)]];
        NSString *str = [freshData toHexString];
        str = [str stringByReplacingOccurrencesOfString:@"fd" withString:@"fe"];
        str = [str stringByAppendingString:@"ble"];
        return str;
    }
    return @"";
}

+(int)sendCmd:(NSData *)data{
    if(data.length >= 4){
        NSData *sdata = [data subdataWithRange:NSMakeRange(3, 1)];
        return [sdata ToByteShort];
    }
    return 0;
}

+(int)sendStep:(NSData *)data{
    if(data.length >= 5){
        NSData *sdata = [data subdataWithRange:NSMakeRange(4, 1)];
        return [sdata ToByteShort];
    }
    return 0;
}

/*
 * 发送数据
 * send data
 */

+ (void)sendCommandData:(NSData *)command completion:(void (^ _Nullable)(HABleModel *bleModel))completion
{
    if(command.length < 4){
        DDLogInfo(@"======sendCommon length is to short");
        return;
    }
    HABleManager *eleMgr = [HABleManager sharedManager];
    if (!eleMgr.writeCharacter) {
        DDLogInfo(@"======eleMgr writeCharacter is empty");
        return;
    }
    
    NSString *cmdHeader = [self dataToStringTag:command];
    HABleModel *bleModel = [[HABleModel alloc] init];
    bleModel.bleCompleHander = completion;
    if(eleMgr.currentPeri) {
        eleMgr.bleModelDictionary[cmdHeader] = bleModel;
        dispatch_block_t commandTask = ^{
            DDLogInfo(@"=======will write data:%@",command);
            [eleMgr.currentPeri writeValue:command
                         forCharacteristic:eleMgr.writeCharacter
                                      type:CBCharacteristicWriteWithResponse];
            int sendCmd = [self sendCmd:command];
            int sendStep = [self sendStep:command];
            if(sendCmd == 1 && sendStep == 4){
                DDLogInfo(@"=========sendCommandData authorized,command is %@",command);
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:BLUETOOTHVERIFYSUCCESS object:nil];
                    if(eleMgr.successBlock){
                        eleMgr.currentPeri.authorized = @(YES);
                        eleMgr.successBlock(eleMgr.centralManager, eleMgr.currentPeri);
                    }
                });
            }
        };
        dispatch_async(eleMgr.eklCommandQueue, commandTask);
    }
}
@end
